#include "BondDataCenter.h"

#include <bondlib/ABBondPriceInfo.h>
#include <bondlib/BondCDCPriceInfo.h>
#include <bondlib/BondCSIPriceInfo.h>
#include <bondlib/BondContainer.h>
#include <bondlib/BondDeal/PanoramicBondDealContainer.h>
#include <bondlib/BondLiquidity.h>
#include <bondlib/HighYieldBond.h>
#include <bondlib/IssuerLiquidity.h>
#include <bondlib/MarketMakeTarget.h>
#include <bondlib/RealTimeDeal/BondMarketStreamV2.h>
#include <bondlib/SSCompanyReportManager.h>
#include <bondlib/SectorBond.h>
#include <bondlib/ThirdPartyGuarantee.h>
#include <core/Events.h>
#include <core/sharedata/login_data.h>
#include <core/sync/lock.h>
#include <core/time/system_time.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/SSMsgStruct.h>
#include <qbprotocol/include/SSQBAModel.h>
#include <qbprotocol/include/rdProto.h>
#include <qbtools/message/MessagePoster.h>
#include <uam/ServerTimeMgr.h>
#include <uam/UserAccountManager.h>

#include "BondUtility.h"
#include "QbMessageProcess.h"

using namespace qb;

static void makeCdcReq(qb::proto::Message& msg, qb::SSRequestMsg* req) {
  qb::proto::Message::List sublist;
  auto& auth = SSUserAccountManager::instance().GetCDCAutority();
  for (auto iter = auth.begin(); iter != auth.end(); ++iter) {
    sublist.push_back(iter->first);
  }
  qb::proto::VariantMap submsg;
  submsg.SetList("List", sublist);
  msg.SetMap("xQBCDCPriceAllReq", submsg);
}

static void makeBestPriceReq(qb::proto::Message& msg, qb::SSRequestMsg* req) {
  SSUserAccountManager& uam = SSUserAccountManager::instance();
  qb::proto::Message::List company_id_list;
  qb::proto::VariantMap submsg;
  QBBestPriceReq_t* pdata = (QBBestPriceReq_t*)req->m_pRequest;
  msg.setString("UserName",
                uam.GetUserInfo().m_UserAccount);  // 用于查问题时区分用户请求
  if (req->m_FuncID == E_FID_QB_BEST_PRICE_REQ)
    msg.setString("IMQ_RequestType", "BONDOFFER_V2");
  else
    msg.setString("IMQ_RequestType", "BONDOFFER");
  for (std::list<xQBBestPriceItem_t>::const_iterator it = pdata->m_List.begin();
       it != pdata->m_List.end(); ++it) {
    submsg.clear();
    submsg.SetString("IMQ_CompanyID", it->m_BrokerID);
    submsg.SetInt32("IMQ_VersionFrom", it->m_VersionFrom);
    submsg.SetInt32("IMQ_VersionTo", it->m_VersionTo);
    if (strcmp(it->m_BrokerID, "e") != 0) {
      int nID = atoi(it->m_BrokerID);
      if (!uam.IsBrokerBondAvailable(nID)) {
        if (!uam.IsBrokerNCDAvailable(nID)) {
          continue;
        } else {
          submsg.setString("BusinessCode", "NCD");
        }
      } else {
        if (!uam.IsBrokerNCDAvailable(nID)) {
          submsg.setString("BusinessCode", "BOND");
        }
      }
    }
    company_id_list.push_back(submsg);
  }
  if (company_id_list.size() <= 0)
    return;  // 无权限，不请求，add by lance 20170725
  msg.setList("IMQ_CompanyID", company_id_list);
}

static void makeBrokerPriceReg(qb::proto::Message& msg, qb::SSRequestMsg* req) {
  SSUserAccountManager& uam = SSUserAccountManager::instance();
  QBBrokerPriceRegReq_t* pdata = (QBBrokerPriceRegReq_t*)req->m_pRequest;
  qb::proto::VariantMap submsg;
  submsg.SetString("UserId", pdata->m_UserId);
  if (pdata->m_ver > 0) {
    submsg.SetInt32("ver", pdata->m_ver);
  }
  qb::proto::Message::List company_id_list;
  for (std::list<xQBTradeCmpyInfo_c>::const_iterator it = pdata->m_List.begin();
       it != pdata->m_List.end(); ++it) {
    qb::proto::VariantMap listmsg;
    listmsg.SetInt32("Id", it->m_Id);
    listmsg.SetString("Code", it->m_Code);
    if (strcmp(it->m_BrokerID, "e") != 0) {
      if (!uam.IsBrokerBondAvailable(it->m_Id)) {
        if (!uam.IsBrokerNCDAvailable(it->m_Id)) {
          continue;
        } else {
          listmsg.setString("BusinessCode", "NCD");
        }
      } else {
        if (!uam.IsBrokerNCDAvailable(it->m_Id)) {
          listmsg.setString("BusinessCode", "BOND");
        }
      }
    }
    company_id_list.push_back(listmsg);
  }
  if (company_id_list.size() <= 0)
    return;  // 无权限，不请求，add by lance 20170725
  submsg.SetList("List", company_id_list);

  msg.SetMap("xQBBrokerPriceRegReq", submsg);
}

static void ReportWithxQBBondQuote_c(REPORT& quote,
                                     const xQBBestPriceUnit_c& bp) {
  if (0 == strcmp("1", bp.m_symbol)) {
    FIELDCOPY(quote.m_bidinfo.m_id, bp.m_id);
    FIELDCOPY(quote.m_bidinfo.m_bp_status, bp.m_bp_status);
    FIELDCOPY(quote.m_bidinfo.m_flag_bargain, bp.m_flag_bargain);
    FIELDCOPY(quote.m_bidinfo.m_flag_relation, bp.m_flag_relation);
    FIELDCOPY(quote.m_bidinfo.m_flag_vip, bp.m_flag_vip);
    FIELDCOPY(quote.m_bidinfo.m_flag_bad, bp.m_flag_bad);
    FIELDCOPY(quote.m_bidinfo.m_price_status, bp.m_price_status);
    FIELDCOPY(quote.m_bidinfo.m_rebate, bp.m_rebate);
    FIELDCOPY(quote.m_bidinfo.m_return_point, bp.m_return_point);
    FIELDCOPY(quote.m_bidinfo.m_clean_price, bp.m_clean_price);
    FIELDCOPY(quote.m_bidinfo.m_full_price, bp.m_full_price);
    FIELDCOPY(quote.m_bidinfo.m_sPrice, bp.m_price);
    FIELDCOPY(quote.m_bidinfo.m_quotetype, bp.m_quotetype);
    FIELDCOPY(quote.m_bidinfo.m_sVolume, bp.m_volume);
    FIELDCOPY(quote.m_bidinfo.m_description, bp.m_price_description);
    FIELDCOPY(quote.m_bidinfo.m_interpret, bp.m_interpret);
    FIELDCOPY(quote.m_bidinfo.m_yield_price, bp.m_yield);

    quote.m_bidinfo.m_create_time = bp.m_create_time;
    quote.m_bidinfo.m_time = bp.m_modify_time;

    // 删除末尾中文字符
    unsigned int ll = sizeof(quote.m_bidinfo.m_description);  // 128
    if ((int)strlen(quote.m_bidinfo.m_description) >= ll - 1) {
      const char* pos = quote.m_bidinfo.m_description + ll - 1;
      int n = ll - 1;
      while (n >= 0) {
        pos--;
        n--;
        if (*pos >= 0 && *pos < 0x80) break;
      }
      n++;
      while (n < (int)ll - 3) {
        n += 2;
      }
      quote.m_bidinfo.m_description[n] = 0x0;
    }
  } else if (0 == strcmp("-1", bp.m_symbol)) {
    FIELDCOPY(quote.m_askinfo.m_id, bp.m_id);
    FIELDCOPY(quote.m_askinfo.m_bp_status, bp.m_bp_status);
    FIELDCOPY(quote.m_askinfo.m_flag_bargain, bp.m_flag_bargain);
    FIELDCOPY(quote.m_askinfo.m_flag_relation, bp.m_flag_relation);
    FIELDCOPY(quote.m_askinfo.m_flag_vip, bp.m_flag_vip);
    FIELDCOPY(quote.m_askinfo.m_flag_bad, bp.m_flag_bad);
    FIELDCOPY(quote.m_askinfo.m_price_status, bp.m_price_status);
    FIELDCOPY(quote.m_askinfo.m_rebate, bp.m_rebate);
    FIELDCOPY(quote.m_askinfo.m_return_point, bp.m_return_point);
    FIELDCOPY(quote.m_askinfo.m_clean_price, bp.m_clean_price);
    FIELDCOPY(quote.m_askinfo.m_full_price, bp.m_full_price);
    FIELDCOPY(quote.m_askinfo.m_sPrice, bp.m_price);
    FIELDCOPY(quote.m_askinfo.m_quotetype, bp.m_quotetype);
    FIELDCOPY(quote.m_askinfo.m_sVolume, bp.m_volume);
    FIELDCOPY(quote.m_askinfo.m_description, bp.m_price_description);
    FIELDCOPY(quote.m_askinfo.m_interpret, bp.m_interpret);
    FIELDCOPY(quote.m_askinfo.m_yield_price, bp.m_yield);

    quote.m_askinfo.m_create_time = bp.m_create_time;
    quote.m_askinfo.m_time = bp.m_modify_time;

    // 删除末尾中文字符
    unsigned int ll = sizeof(quote.m_askinfo.m_description);  // 128
    if ((int)strlen(quote.m_askinfo.m_description) >= ll - 1) {
      const char* pos = quote.m_askinfo.m_description + ll - 1;
      int n = ll - 1;
      while (n >= 0) {
        pos--;
        n--;
        if (*pos >= 0 && *pos < 0x80) break;
      }
      n++;
      while (n < (int)ll - 3) {
        n += 2;
      }
      quote.m_askinfo.m_description[n] = 0x0;
    }
  }
}

static bool UpdateBondInfoByREPORT(CBondCompanyRep* pRep, REPORT* pReport,
                                   bool bVers,
                                   int bidask /*1--bid ,-1 ask, 0- 中间价*/) {
  // pReport从网络消息中解析而来
  if (!pReport || !pRep) return false;

  REPORT report;
  memset(&report, 0, sizeof(report));

  if (strcmp(pReport->m_price_status, "0") == 0)  // 无效报价
  {
    if (pReport->m_company_id[0] != 'e') {  // 非交易所，填充bid/ofr
      if (bidask == 1 && strlen(pReport->m_bidinfo.m_sPrice) == 0) {
        FIELDCOPY(pReport->m_bidinfo.m_sPrice, "Bid");
      } else if (bidask == -1 && strlen(pReport->m_askinfo.m_sPrice) == 0) {
        FIELDCOPY(pReport->m_askinfo.m_sPrice, "Ofr");
      }
    }
  } else  // 有效报价
  {
    if (strcmp(pReport->m_bp_status, "0") !=
        0)  // 非0时，清空本地缓存数据。（0表示发布）
    {
      if (bidask == 1) {
        memset(pReport->m_bidinfo.m_quotetype, 0,
               sizeof(pReport->m_bidinfo.m_quotetype));
        memset(pReport->m_bidinfo.m_flag_bargain, 0,
               sizeof(pReport->m_bidinfo.m_flag_bargain));
        memset(pReport->m_bidinfo.m_flag_relation, 0,
               sizeof(pReport->m_bidinfo.m_flag_relation));
        memset(pReport->m_bidinfo.m_flag_vip, 0,
               sizeof(pReport->m_bidinfo.m_flag_vip));
        memset(pReport->m_bidinfo.m_flag_bad, 0,
               sizeof(pReport->m_bidinfo.m_flag_bad));
        memset(pReport->m_bidinfo.m_rebate, 0,
               sizeof(pReport->m_bidinfo.m_rebate));
        memset(pReport->m_bidinfo.m_description, 0,
               sizeof(pReport->m_bidinfo.m_description));
        memset(pReport->m_bidinfo.m_clean_price, 0,
               sizeof(pReport->m_bidinfo.m_clean_price));
        memset(pReport->m_bidinfo.m_full_price, 0,
               sizeof(pReport->m_bidinfo.m_full_price));
        memset(pReport->m_bidinfo.m_sPrice, 0,
               sizeof(pReport->m_bidinfo.m_sPrice));
        memset(pReport->m_bidinfo.m_sVolume, 0,
               sizeof(pReport->m_bidinfo.m_sVolume));
        memset(pReport->m_bidinfo.m_yield_price, 0,
               sizeof(pReport->m_bidinfo.m_yield_price));
        memset(pReport->m_bidinfo.m_interpret, 0,
               sizeof(pReport->m_bidinfo.m_interpret));
      }
      if (bidask == -1) {
        memset(pReport->m_askinfo.m_quotetype, 0,
               sizeof(pReport->m_askinfo.m_quotetype));
        memset(pReport->m_askinfo.m_flag_bargain, 0,
               sizeof(pReport->m_askinfo.m_flag_bargain));
        memset(pReport->m_askinfo.m_flag_relation, 0,
               sizeof(pReport->m_askinfo.m_flag_relation));
        memset(pReport->m_askinfo.m_flag_vip, 0,
               sizeof(pReport->m_askinfo.m_flag_vip));
        memset(pReport->m_askinfo.m_flag_bad, 0,
               sizeof(pReport->m_askinfo.m_flag_bad));
        memset(pReport->m_askinfo.m_rebate, 0,
               sizeof(pReport->m_askinfo.m_rebate));
        memset(pReport->m_askinfo.m_description, 0,
               sizeof(pReport->m_askinfo.m_description));
        memset(pReport->m_askinfo.m_clean_price, 0,
               sizeof(pReport->m_askinfo.m_clean_price));
        memset(pReport->m_askinfo.m_full_price, 0,
               sizeof(pReport->m_askinfo.m_full_price));
        memset(pReport->m_askinfo.m_sPrice, 0,
               sizeof(pReport->m_askinfo.m_sPrice));
        memset(pReport->m_askinfo.m_sVolume, 0,
               sizeof(pReport->m_askinfo.m_sVolume));
        memset(pReport->m_askinfo.m_yield_price, 0,
               sizeof(pReport->m_askinfo.m_yield_price));
        memset(pReport->m_askinfo.m_interpret, 0,
               sizeof(pReport->m_askinfo.m_interpret));
      }
    } else if (pReport->m_company_id[0] != 'e') {  // 非交易所，填充bid/ofr
      if (bidask == 1 && strlen(pReport->m_bidinfo.m_sPrice) == 0) {
        memset(pReport->m_bidinfo.m_quotetype, 0,
               sizeof(pReport->m_bidinfo.m_quotetype));
        FIELDCOPY(pReport->m_bidinfo.m_sPrice, "Bid");
      } else if (bidask == -1 && strlen(pReport->m_askinfo.m_sPrice) == 0) {
        memset(pReport->m_askinfo.m_quotetype, 0,
               sizeof(pReport->m_askinfo.m_quotetype));
        FIELDCOPY(pReport->m_askinfo.m_sPrice, "Ofr");
      }
    }
  }

  bool bRet = pRep->GetCompanyRepByKey(pReport->m_company_id, report);
  if (bRet && bVers && report.m_dwVersion > pReport->m_dwVersion) {
    // TODO: LogReportErrorInfo(report, bidask, "m_dwVersion failed", pReport);
    return false;
  }

  if (bRet) {
    memset(report.m_bp_status, 0, sizeof(report.m_bp_status));
    memset(report.m_price_status, 0, sizeof(report.m_price_status));

    FIELDCOPY(report.m_bp_status, pReport->m_bp_status);
    FIELDCOPY(report.m_price_status, pReport->m_price_status);
    if (bidask == 1 &&
        (report.m_bidinfo.m_create_time <= pReport->m_bidinfo.m_create_time ||
         report.m_bidinfo.m_time <= pReport->m_bidinfo.m_time)) {
      memset(&report.m_bidinfo, 0, sizeof(PRICE));
      report.m_bidinfo = pReport->m_bidinfo;
      if (pReport->m_company_id[0] != 'e' ||
          (pReport->m_company_id[0] == 'e' &&
           pReport->m_tradePrice[0] != '\0')) {
        // 交易所行情，如果成交为空，则不覆盖本地缓存
        FIELDCOPY(report.m_tradePrice, pReport->m_tradePrice);
      }
    } else if (bidask == -1 &&
               (report.m_askinfo.m_create_time <=
                    pReport->m_askinfo.m_create_time ||
                report.m_askinfo.m_time <= pReport->m_askinfo.m_time)) {
      memset(&report.m_askinfo, 0, sizeof(PRICE));
      report.m_askinfo = pReport->m_askinfo;
      if (pReport->m_company_id[0] != 'e' ||
          (pReport->m_company_id[0] == 'e' &&
           pReport->m_tradePrice[0] != '\0')) {
        // 交易所行情，如果成交为空，则不覆盖本地缓存
        FIELDCOPY(report.m_tradePrice, pReport->m_tradePrice);
      }
    } else if (bidask == 0 && report.m_indx_info.m_modify_time <=
                                  pReport->m_indx_info.m_modify_time) {
      report.m_indx_info = pReport->m_indx_info;  // 参考价
    } else {
      // TODO: LogReportErrorInfo(report, bidask, "modifytime is old", pReport);
      return false;
    }

    report.m_create_time = max(pReport->m_time, pReport->m_create_time);
    report.m_time = max(pReport->m_time, pReport->m_create_time);
    report.m_dwVersion = pReport->m_dwVersion;
    report.m_pkg_id = pReport->m_pkg_id;
    pRep->InsertCompanyRep(report);

    // TODO: LogReportInfo(report, bidask, "Storaged", nullptr);
  } else {
    pRep->InsertCompanyRep(*pReport);
    // TODO: LogReportInfo(report, bidask, "CompanyRep not find", nullptr);
  }

  return true;
}
static bool UpdateBondContainerByREPORT(CBondContainer& container,
                                        REPORT* pReport, bool bAddIfNotExist,
                                        bool bVers,
                                        REPORT* pReportLast = nullptr,
                                        int bidask = 0, int local = 0) {
  // pReport 从消息中解析而来
  if (nullptr == pReport) return false;

  int id = 0;
  if (!container.GetBondInfoByKey(pReport->m_sBondKey, pReport->m_sListedMarket,
                                  nullptr, &id))
    return true;

  CBondCompanyRep* prep = BrokerRepMng->GetReportOrAdd(id);
  if (prep && UpdateBondInfoByREPORT(prep, pReport, bVers, bidask)) {
    int nVer = container.GetVersionById(pReport->m_company_id);
    if (nVer < (int)pReport->m_dwVersion) {
      container.UpdateVersionById(pReport->m_company_id, pReport->m_dwVersion,
                                  pReport->m_create_time);
    }
  }

  return true;
}
static void RebuildMixedBestPriceField(REPORT& report) {
  if (strcmp(report.m_bidinfo.m_bp_status, "0") != 0)  // 无效报价
  {
    time_t t = report.m_bidinfo.m_time;
    memset(&report.m_bidinfo, 0, sizeof(PRICE));
    report.m_bidinfo.m_time = t;
    report.m_bidinfo.m_create_time = t;
  } else {  // 有效报价，填充Bid
    if (strcmp(report.m_bidinfo.m_quotetype, "0") == 0 ||
        strlen(report.m_bidinfo.m_sPrice) == 0) {
      FIELDCOPY(report.m_bidinfo.m_quotetype, "0");
      FIELDCOPY(report.m_bidinfo.m_sPrice, "Bid");
      memset(report.m_bidinfo.m_yield_price, 0,
             sizeof(report.m_bidinfo.m_yield_price));
      memset(report.m_bidinfo.m_clean_price, 0,
             sizeof(report.m_bidinfo.m_clean_price));
      memset(report.m_bidinfo.m_full_price, 0,
             sizeof(report.m_bidinfo.m_full_price));
    }
  }

  if (strcmp(report.m_askinfo.m_bp_status, "0") != 0)  // 无效报价
  {
    time_t t = report.m_askinfo.m_time;
    memset(&report.m_askinfo, 0, sizeof(PRICE));
    report.m_askinfo.m_time = report.m_askinfo.m_create_time = t;
  } else {  // 有效报价，填充Ofr
    if (strcmp(report.m_askinfo.m_quotetype, "0") == 0 ||
        strlen(report.m_askinfo.m_sPrice) == 0) {
      FIELDCOPY(report.m_askinfo.m_quotetype, "0");
      FIELDCOPY(report.m_askinfo.m_sPrice, "Ofr");
      memset(report.m_askinfo.m_yield_price, 0,
             sizeof(report.m_askinfo.m_yield_price));
      memset(report.m_askinfo.m_clean_price, 0,
             sizeof(report.m_askinfo.m_clean_price));
      memset(report.m_askinfo.m_full_price, 0,
             sizeof(report.m_askinfo.m_full_price));
    }
  }
}
static void ReportWithxQBMixedBestPrice(REPORT& report,
                                        const xQBMixedBestQuoteUnit_c& unit,
                                        bool isOption) {
  FIELDCOPY(report.m_sBondKey, unit.m_bondkey);
  FIELDCOPY(report.m_sListedMarket, unit.m_listedmarket);
  FIELDCOPY(report.m_company_id, unit.m_contributorId);

  report.m_dwVersion = unit.m_version;
  report.m_price_sel = Trade_Price;
  report.m_create_time = unit.m_modifyTime;
  report.m_time = unit.m_modifyTime;

  FIELDCOPY(report.m_bidinfo.m_id, unit.m_messageSeq);
  FIELDCOPY(report.m_bidinfo.m_company_id, unit.m_bidCompanyId);
  FIELDCOPY(report.m_bidinfo.m_bp_status, unit.m_bidQuoteStatus);
  // FIELDCOPY(report.m_bidinfo.m_price_status, unit.m_bidQuoteStatus);
  FIELDCOPY(report.m_bidinfo.m_sPrice, unit.m_bidPrice);
  FIELDCOPY(report.m_bidinfo.m_yield_price, unit.m_bidYield);
  FIELDCOPY(report.m_bidinfo.m_clean_price, unit.m_bidNetPrice);
  FIELDCOPY(report.m_bidinfo.m_full_price, unit.m_bidFullPrice);
  FIELDCOPY(report.m_bidinfo.m_sVolume, unit.m_bidVolumn);
  FIELDCOPY(report.m_bidinfo.m_interpret, unit.m_bidInterpret);
  FIELDCOPY(report.m_bidinfo.m_quotetype, unit.m_bidQuoteType);
  FIELDCOPY(report.m_bidinfo.m_flag_bargain, unit.m_bidBarginFlag);
  FIELDCOPY(report.m_bidinfo.m_flag_relation, unit.m_bidRelationFlag);
  if (isOption) FIELDCOPY(report.m_bidinfo.m_exercise, unit.m_bidExercise);

  report.m_bidinfo.m_create_time = unit.m_modifyTime;
  report.m_bidinfo.m_time = unit.m_modifyTime;

  FIELDCOPY(report.m_askinfo.m_id, unit.m_messageSeq);
  FIELDCOPY(report.m_askinfo.m_company_id, unit.m_ofrCompanyId);
  FIELDCOPY(report.m_askinfo.m_bp_status, unit.m_ofrQuoteStatus);
  // FIELDCOPY(report.m_askinfo.m_price_status, unit.m_ofrQuoteStatus);
  FIELDCOPY(report.m_askinfo.m_sPrice, unit.m_ofrPrice);
  FIELDCOPY(report.m_askinfo.m_yield_price, unit.m_ofrYield);
  FIELDCOPY(report.m_askinfo.m_clean_price, unit.m_ofrNetPrice);
  FIELDCOPY(report.m_askinfo.m_full_price, unit.m_ofrFullPrice);
  FIELDCOPY(report.m_askinfo.m_sVolume, unit.m_ofrVolumn);
  FIELDCOPY(report.m_askinfo.m_interpret, unit.m_ofrInterpret);
  FIELDCOPY(report.m_askinfo.m_quotetype, unit.m_ofrQuoteType);
  FIELDCOPY(report.m_askinfo.m_flag_bargain, unit.m_ofrBarginFlag);
  FIELDCOPY(report.m_askinfo.m_flag_relation, unit.m_ofrRelationFlag);
  if (isOption) FIELDCOPY(report.m_askinfo.m_exercise, unit.m_ofrExercise);

  report.m_askinfo.m_create_time = unit.m_modifyTime;
  report.m_askinfo.m_time = unit.m_modifyTime;
}
static bool UpdateMixedBestPriceByReport(CBondCompanyRep* pRep, REPORT* pReport,
                                         bool bVers) {
  if (!pReport || !pRep) return false;

  RebuildMixedBestPriceField(*pReport);

  REPORT report;
  memset(&report, 0, sizeof(report));
  bool bRet = pRep->GetCompanyRepByKey(pReport->m_company_id, report);
  if (bRet && bVers && report.m_dwVersion > pReport->m_dwVersion) {
    log_info(
        "[Version Check] contributorId = %s Client Version = %d, New Price "
        "Version=%d",
        report.m_company_id, report.m_dwVersion, pReport->m_dwVersion);
    return false;
  }

  if (bRet) {
    memcpy(&report, pReport, sizeof(REPORT));
    pRep->InsertCompanyRep(report);
  } else {
    pRep->InsertCompanyRep(*pReport);
  }
  return true;
}
static bool UpdateMixedBestPrice(REPORT* pReport) {
  int bondIndex = CBondContainer::instance().GetBondIndex(
      pReport->m_sBondKey, pReport->m_sListedMarket);
  if (!CBondContainer::instance().IsValidIndex(bondIndex)) return false;

  CBondCompanyRep* prep =
      GetBrokerMixedBPReportManager()->GetReportOrAdd(bondIndex);
  if (prep) {
    UpdateMixedBestPriceByReport(prep, pReport, true);
    int nVer = CBondContainer::instance().GetVersionById(pReport->m_company_id);
    if (nVer < (int)pReport->m_dwVersion) {
      CBondContainer::instance().UpdateVersionById(
          pReport->m_company_id, pReport->m_dwVersion, pReport->m_create_time);
    }
  }
  return true;
}

BondDataCenter& BondDataCenter::instance() {
  static BondDataCenter s_bd;
  return s_bd;
}

void BondDataCenter::requestQBACDCPriceNonSpecial() {
  qb::SSRequestMsg msg;
  msg.m_pRequest = nullptr;
  msg.m_FuncID = E_FID_QBA_CDC_PRICE_ALL_REQ_V3;
  MessagePoster poster(&msg, makeCdcReq);
  poster.send(this);
}

void BondDataCenter::requestQBACDCPriceSpecial() {
  qb::SSRequestMsg msg;
  msg.m_pRequest = nullptr;
  msg.m_FuncID = E_FID_QBA_CDC_PRICE_SPECIAL_REQ;
  MessagePoster poster(&msg, makeCdcReq);
  poster.send(this);
}

void BondDataCenter::requestBestPrice() {
  CBondContainer& bc = CBondContainer::instance();
  if (bc.CheckVersion()) {
    bc.ClearCDCDataAll();
    bc.ClearCSData();
  }

  qb::SSRequestMsg Req;
  Req.m_FuncID = E_FID_QB_BEST_PRICE_REQ;

  xQBBestPriceItem_t bpItem;
  const CBrokerList& brokerlist =
      SSUserAccountManager::instance().GetReadonlyBroker();
  std::vector<int> vctsortid = brokerlist.GetSortKey();
  for (auto itor = vctsortid.begin(); itor != vctsortid.end(); itor++) {
    CBrokerList::BrokerMap::const_iterator bk =
        brokerlist.GetBrokerMap().find(*itor);
    if (bk == brokerlist.GetBrokerMap().end()) continue;
    if (!bk->second.m_enableFlag_BOND && !bk->second.m_enableFlag_NCD) continue;

    QBBestPriceReq_t req;
    QBBestPriceReq_t* ptr = &req;

    memset(&bpItem, 0, sizeof(xQBBestPriceItem_t));
    FMTBUF(bpItem.m_BrokerID, "%d", bk->second.m_brokerID);
    bpItem.m_VersionFrom = bc.GetVersionById(bpItem.m_BrokerID);
    bpItem.m_VersionTo = -1;
    ptr->m_List.push_back(bpItem);
    Req.m_pRequest = (void*)ptr;
    Req.m_RequestID = atol(bpItem.m_BrokerID);

    MessagePoster poster(&Req, makeBestPriceReq);
    poster.send(this);

    log_debug("Request Best Price:%s,%s,VersionFrom=%d,VersionTo=%d",
              bk->second.m_brokerENName.c_str(), bpItem.m_BrokerID,
              bpItem.m_VersionFrom, bpItem.m_VersionTo);
  }
}

void BondDataCenter::requestBrokerPriceReg() {
  qb::SSRequestMsg Req;
  Req.m_FuncID = E_FID_QB_BROKER_BESTPRICE_REGISTER;

  QBBrokerPriceRegReq_t req;
  QBBrokerPriceRegReq_t* ptr = &req;

  FIELDCOPY(ptr->m_UserId,
            SSUserAccountManager::instance().GetUserInfo().m_UserId);
  xQBTradeCmpyInfo_c qbInfo;
  const CBrokerList& brokerlist =
      SSUserAccountManager::instance().GetReadonlyBroker();
  for (CBrokerList::BrokerMap::const_iterator itor =
           brokerlist.GetBrokerMap().begin();
       itor != brokerlist.GetBrokerMap().end(); itor++) {
    if (!itor->second.m_enableFlag_BOND && !itor->second.m_enableFlag_NCD)
      continue;
    memset(&qbInfo, 0, sizeof(qbInfo));
    qbInfo.m_Id = itor->second.m_brokerID;
    ptr->m_List.push_back(qbInfo);
  }
  ptr->m_ver = 1;
  Req.m_pRequest = (void*)ptr;
  MessagePoster poster(&Req, makeBrokerPriceReg);
  poster.send();

  ptr->m_ver = -1;
  Req.m_pRequest = (void*)ptr;
  Req.m_FuncID = E_FID_QB_BROKER_DEAL_REGISTER;
  MessagePoster poster2(&Req, makeBrokerPriceReg);
  poster2.send();
}

void BondDataCenter::requestQBMarketStreamDeal() {
  qb::SSRequestMsg Req;
  memset(&Req, 0, sizeof(qb::SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_MARKET_STREAM_DEAL_REQ;

  QBMarketStreamReq_t req;
  QBMarketStreamReq_t* ptr = &req;

  xQBTradeCmpyInfo_c qbInfo;
  const CBrokerList& brokerlist =
      SSUserAccountManager::instance().GetReadonlyBroker();
  for (auto itor = brokerlist.GetBrokerMap().begin();
       itor != brokerlist.GetBrokerMap().end(); itor++) {
    if (!itor->second.m_enableFlag_BOND && !itor->second.m_enableFlag_NCD) {
      continue;
    }
    memset(&qbInfo, 0, sizeof(qbInfo));
    qbInfo.m_Id = itor->second.m_brokerID;
    ptr->m_List.push_back(qbInfo);
  }

  // 报价类型
  xQBTradeType_c qbType;
  memset(&qbType, 0, sizeof(xQBTradeType_c));
  FIELDCOPY(qbType.TradeType, "TKN");
  req.m_TradeTypeList.push_back(qbType);

  memset(&qbType, 0, sizeof(xQBTradeType_c));
  FIELDCOPY(qbType.TradeType, "GVN");
  req.m_TradeTypeList.push_back(qbType);

  memset(&qbType, 0, sizeof(xQBTradeType_c));
  FIELDCOPY(qbType.TradeType, "TRD");
  req.m_TradeTypeList.push_back(qbType);

  req.m_IndexFrom = 0;
  req.m_IndexTo = -1;
  req.m_bondkey[0] = '\0';
  req.m_traderId[0] = '\0';

  Req.m_pRequest = (void*)ptr;

  MessagePoster poster(&Req, &qbbond::makeMarketStreamDealReq);
  poster.send(this);
}

void BondDataCenter::requestAllCSIV2() {
  if (!SSUserAccountManager::instance().GetCSIAuthorityFlag()) return;

  SSRequestMsg Req;
  Req.m_FuncID = E_FID_CSI_PRICE_ALL_REQ_V2;

  MessagePoster poster(&Req, nullptr);
  poster.send(this);
}

void BondDataCenter::requestBondLiquidity() {
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_BOND_LIQUIDITY_FULL_REQ_V2;
  Req.m_pRequest = nullptr;
  MessagePoster poster(
      &Req, [=](qb::proto::Message& msg, qb::SSRequestMsg* req) {
        qb::proto::VariantMap submsg;
        submsg.setString(
            "UserId", SSUserAccountManager::instance().GetUserInfo().m_UserId);
        submsg.setString(
            "CompanyID",
            SSUserAccountManager::instance().GetUserInfo().m_CompanyId);
        msg.SetMap("xQBBondLiquidityFullReq_c", submsg);
      });
  poster.send(this);
}

void BondDataCenter::requestIssuerLiquidity() {
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_ISSUER_LIQUIDITY_FULL_REQ_V2;
  Req.m_pRequest = nullptr;
  MessagePoster poster(
      &Req, [=](qb::proto::Message& msg, qb::SSRequestMsg* req) {
        qb::proto::VariantMap submsg;
        submsg.setString(
            "UserId", SSUserAccountManager::instance().GetUserInfo().m_UserId);
        submsg.setString(
            "CompanyID",
            SSUserAccountManager::instance().GetUserInfo().m_CompanyId);
        msg.SetMap("xQBIssuerLiquidityFullReq_c", submsg);
      });
  poster.send(this);
}

void BondDataCenter::requestHighYieldBond() {
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_HIGT_YIELD_BOND_QRY;
  Req.m_pRequest = nullptr;
  MessagePoster poster(
      &Req, [=](qb::proto::Message& msg, qb::SSRequestMsg* req) {
        qb::proto::VariantMap submsg;
        submsg.setString(
            "UserId", SSUserAccountManager::instance().GetUserInfo().m_UserId);
        submsg.setString(
            "CompanyID",
            SSUserAccountManager::instance().GetUserInfo().m_CompanyId);
        msg.SetMap("xQBHighYieldBondListReq_t", submsg);
      });
  poster.send(this);
}

void BondDataCenter::requestThirdPartyGuarantee() {
  CThirdPartyGuarantee::instance().ClearData();
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_THIRD_PARTY_GUARANTEE_QRY;
  Req.m_pRequest = nullptr;
  MessagePoster poster(
      &Req, [=](qb::proto::Message& msg, qb::SSRequestMsg* req) {
        qb::proto::VariantMap submsg;
        submsg.setString(
            "UserId", SSUserAccountManager::instance().GetUserInfo().m_UserId);
        submsg.setString(
            "CompanyID",
            SSUserAccountManager::instance().GetUserInfo().m_CompanyId);
        msg.SetMap("xQBThirdPartyGuaranteeListReq_t", submsg);
      });
  poster.send(this);
}

void BondDataCenter::requestSectorBond() {
  SectorBond::instance().ClearData();
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_SECTOR_BOND_REQ;

  SectorBondReq req;
  FIELDCOPY(req.m_userId,
            SSUserAccountManager::instance().GetUserInfo().m_UserId);
  req.m_sectorList = SectorBond::instance().GetSectorVector();
  Req.m_pRequest = (void*)&req;

  MessagePoster poster(
      &Req, [=](qb::proto::Message& msg, qb::SSRequestMsg* req) {
        SectorBondReq* pdata = (SectorBondReq*)req->m_pRequest;
        qb::proto::VariantMap submsg;
        submsg.setString(
            "UserId", SSUserAccountManager::instance().GetUserInfo().m_UserId);
        qb::proto::Message::List list;
        for (auto it : pdata->m_sectorList) list.push_back(it);
        submsg.SetList("sectorList", list);
        msg.SetMap("SectorBondReq", submsg);
      });
  poster.send(this);
}

void BondDataCenter::requestMarketMakeTarget() {
  CMarketMakeTarget::instance().ClearData();
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_MARKETMAKE_TARGET_BOND_REQ;  // 50293,

  xQBMarketMakeTargetReq_c req;
  xQBMarketMakeTargetReq_c* ptr = &req;
  std::vector<string> vSectionId = {"07120102", "07120104", "07120101",
                                    "07120103", "07120202", "07120201"};
  for (auto id : vSectionId) {
    ptr->m_listSectionId.push_back(id);
  }
  Req.m_pRequest = (void*)ptr;

  MessagePoster poster(&Req,
                       [=](qb::proto::Message& msg, qb::SSRequestMsg* req) {
                         xQBMarketMakeTargetReq_c* pdata =
                             (xQBMarketMakeTargetReq_c*)req->m_pRequest;
                         qb::proto::Message::List list;
                         for (auto it = pdata->m_listSectionId.begin();
                              it != pdata->m_listSectionId.end(); ++it)
                           list.push_back(*it);
                         msg.SetList("xQBMarketMakeTargetReq", list);
                       });
  poster.send(this);
}

void BondDataCenter::requestQBCompanySort(int nEnableBroker,
                                          std::vector<int> stlSortShow) {
  QBCompanySortReq_t req;
  SSUserAccountManager& uam = SSUserAccountManager::instance();
  CUserAccountInfo stUserInfo = uam.GetUserInfo();
  CBrokerList::Writer writer = uam.GetBroker();

  writer.ClearSortKey();
  for (int i = 0; i < nEnableBroker; i++) {
    int nID = stlSortShow[i];
    writer.AddSortKey(nID);
  }

  SSRequestMsg msg;
  msg.m_pRequest = nullptr;
  msg.m_FuncID = E_FID_QB_COMPANY_SORT_REQ;
  MessagePoster poster(
      &msg, [=](qb::proto::Message& msg, qb::SSRequestMsg* req) {
        qb::proto::Message::List company_id_list;
        for (auto it = stlSortShow.begin(); it != stlSortShow.end(); ++it) {
          company_id_list.push_back(*it);
        }
        qb::proto::VariantMap submsg;
        submsg.SetList("List", company_id_list);
        submsg.setString(
            "UserId", SSUserAccountManager::instance().GetUserInfo().m_UserId);
        submsg.SetInt32("SaveType", 1);
        msg.SetMap("xQBCompanySortReq", submsg);
      });

  poster.send(this);
  emit companySorted();
}

void BondDataCenter::requestMixedBestQuote(const char* contributorId) {
  doMixedBestQuote(E_FID_QB_MIXED_BESTQUOTE_REQ, contributorId);
}

void BondDataCenter::requestABBondPrice() {
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_ABBOND_RECOMMEND_PRICE_REQ;

  xQBAbBondRecommendPriceReq_t req;
  FIELDCOPY(req.m_UserId,
            SSUserAccountManager::instance().GetUserInfo().m_UserId);
  FIELDCOPY(req.m_CompanyId,
            SSUserAccountManager::instance().GetUserInfo().m_CompanyId);
  req.m_FromVer = CABBondPriceInfo::instance().GetVersion();
  Req.m_pRequest = (void*)&req;

  MessagePoster poster(&Req,
                       [=](qb::proto::Message& msg, qb::SSRequestMsg* req) {
                         qb::proto::VariantMap submsg;
                         xQBAbBondRecommendPriceReq_t* pdata =
                             (xQBAbBondRecommendPriceReq_t*)req->m_pRequest;
                         submsg.setString("UserId", pdata->m_UserId);
                         submsg.setString("CompanyID", pdata->m_CompanyId);
                         submsg.setUint32("FromVer", pdata->m_FromVer);
                         msg.SetMap("xQBAbBondRecommendPriceReq", submsg);
                       });
  poster.send(this);
}

void BondDataCenter::onDataArrived(const qb::SSAckMsg& msg) {
  int funcId = msg.m_FuncID;
  if (funcId == E_FID_QB_EX_DEAL_PUSH_V2 || funcId == E_FID_QB_EX_DEAL_PUSH ||
      funcId == E_FID_QB_MARKET_STREAM_DEAL_PUSH ||
      funcId == E_FID_QB_CFETS_DEAL_PUSH) {
    if (msg.m_FuncID == E_FID_QB_MARKET_STREAM_DEAL_PUSH) {
      saveMarketStreamDeal(msg);
    }

    notifyMarketStreamDeal(msg);
  } else if (funcId == E_FID_QBA_CDC_PRICE_ALL_REQ_V3 ||
             funcId == E_FID_QBA_CDC_PRICE_SPECIAL_REQ) {
    xQBACDCPriceList_c* pdata = (xQBACDCPriceList_c*)msg.m_pRet;
    if (!pdata) return;

    const size_t nSize = pdata->m_List.size();
    if (nSize == 0) return;

    SCOPED_LOCK(CBondCDCPriceInfo::instance().GetMutex());
    for (std::list<xQBACDCPriceUnit_c>::const_iterator it =
             pdata->m_List.begin();
         it != pdata->m_List.end(); ++it) {
      bool market_empty = strcmp(it->m_listedmarket, "") == 0;
      int nBondIndex = CBondContainer::instance().GetBondIndex(
          it->m_bond_key,
          market_empty ? CBondContainer::lmCIB : it->m_listedmarket);
      if (!CBondContainer::instance().IsValidIndex(nBondIndex)) {
        log_error("[BOND]can not find bond:%s  %s", it->m_bond_key,
                  market_empty ? CBondContainer::lmCIB : it->m_listedmarket);
        continue;
      }
      // 插入中债估值相关数据
      CBondCDCPriceInfo::instance().Add(
          nBondIndex, *it, (funcId == E_FID_QBA_CDC_PRICE_SPECIAL_REQ));
    }
    if (msg.m_IsReceving == 0) {
      // if (func_id == E_FID_QBA_CDC_PRICE_ALL_REQ_V3)m_bCDCPriceUpdated =
      // true; else m_bCDCSpecialPriceUpdated = true;
      CPanoramicBondDealContainer::instance().ReCalculaterAllCDC();
    }
  } else if (funcId == E_FID_QB_BEST_PRICE_REQ) {
    REPORT report;
    xQBBestPriceListAck_c* pdata = (xQBBestPriceListAck_c*)msg.m_pRet;
    if (!pdata) return;
    const size_t nSize = pdata->m_List.size();
    if (nSize == 0) return;

    SSUserAccountManager& uam = SSUserAccountManager::instance();
    std::list<xQBBestPriceUnit_c>::const_iterator it = pdata->m_List.begin();

    bool bIsEx = strcmp(it->m_company_id, "e") == 0;

    bool BondValid = bIsEx || uam.IsBrokerBondAvailable(it->m_company_id);
    bool NCDValid = bIsEx || uam.IsBrokerNCDAvailable(it->m_company_id);
    if (!BondValid && !NCDValid) {
      return;
    }

    if (!BondValid && strcmp(pdata->m_BusinessCode, "BOND") == 0) {
      return;
    }
    if (!NCDValid && strcmp(pdata->m_BusinessCode, "NCD") == 0) {
      return;
    }

    for (; it != pdata->m_List.end(); ++it) {
      int nID = CBondContainer::instance().GetBondIndex(it->m_bondkey,
                                                        it->m_listedmarket);
      if (nID < 0) continue;

      const CBondInfo& bond = CBondContainer::instance().ElementAtR(nID);
      if (!bond.IsValidBond()) continue;
      bool bNCD = bond.IsBondNCD();
      if (bNCD && !NCDValid) continue;
      if (!bNCD && !BondValid) continue;
      bool bAuthValid{true};
      bIsEx = strcmp(it->m_company_id, "e") == 0;
      if (bIsEx) {
        bAuthValid = uam.HasExchangeAuth(bond.GetListedMarket());
      }
      if (!bAuthValid) continue;

      memset(&report, 0, sizeof(REPORT));
      FIELDCOPY(report.m_sBondKey, it->m_bondkey);
      FIELDCOPY(report.m_sListedMarket, it->m_listedmarket);
      FIELDCOPY(report.m_company_id, it->m_company_id);
      FIELDCOPY(report.m_bp_status, it->m_bp_status);
      FIELDCOPY(report.m_price_status, it->m_price_status);

      report.m_dwVersion = it->m_version;
      report.m_price_sel = Trade_Price;
      report.m_create_time = it->m_create_time;
      report.m_time = it->m_modify_time;
      ReportWithxQBBondQuote_c(report, *it);

      if (bIsEx && bond.IsTransBond()) {
        int sym = atoi(it->m_symbol);
        if (sym == 1) {
          if (it->m_clean_price[0] != '\0')
            FIELDCOPY(report.m_bidinfo.m_sPrice, it->m_clean_price);
          else
            FIELDCOPY(report.m_bidinfo.m_sPrice, it->m_price);
        } else if (sym == -1) {
          if (it->m_clean_price[0] != '\0')
            FIELDCOPY(report.m_askinfo.m_sPrice, it->m_clean_price);
          else
            FIELDCOPY(report.m_askinfo.m_sPrice, it->m_price);
        }

        if (it->m_trade_clear_Price[0] != '\0')
          FIELDCOPY(report.m_tradePrice, it->m_trade_clear_Price);
        else
          FIELDCOPY(report.m_tradePrice, it->m_tradePrice);
      } else {
        FIELDCOPY(report.m_tradePrice, it->m_tradePrice);
      }

      if (funcId == E_FID_QB_BONDCOP_BEST_PRICE_REQ) {
        //?请求机构二级债券最优报价
        // TODO: UpdateQuoteManagerByREPORT(HYQuotMng, &report, false,
        // atoi(it->m_symbol));
      } else {
        UpdateBondContainerByREPORT(CBondContainer::instance(), &report, true,
                                    false, nullptr, atoi(it->m_symbol));
      }
    }
    if (msg.m_IsReceving == 0) {
      emit bestPriceReqArrivedAll();
    }

    msgEventDispatcher.dispatch(EVENT_MESSAGE_ARRIVED, &msg);
  } else if (funcId == E_FID_QB_MARKET_STREAM_DEAL_REQ) {
    saveMarketStreamDeal(msg);
    notifyMarketStreamDeal(msg);
  } else if (funcId == E_FID_QB_BEST_PRICE_PUSH_V2) {
    REPORT report;
    xQBBestPriceListAck_c* pdata = (xQBBestPriceListAck_c*)msg.m_pRet;
    if (!pdata || pdata->m_List.size() == 0) return;

    SSUserAccountManager& uam = SSUserAccountManager::instance();
    std::list<xQBBestPriceUnit_c>::const_iterator it = pdata->m_List.begin();

    bool bIsEx = strcmp(it->m_company_id, "e") == 0;
    bool BondValid = bIsEx || uam.IsBrokerBondAvailable(it->m_company_id);
    bool NCDValid = bIsEx || uam.IsBrokerNCDAvailable(it->m_company_id);
    if (!BondValid && !NCDValid) {
      return;
    }
    if (!BondValid && strcmp(pdata->m_BusinessCode, "BOND") == 0) {
      return;
    }
    if (!NCDValid && strcmp(pdata->m_BusinessCode, "NCD") == 0) {
      return;
    }

    std::map<std::string, QList<xQBBestPriceUnit_c>> m_bondBestPrice;
    QList<xQBBestPriceUnit_c> m_bpAll;
    int nMinVer = it->m_version;
    int nMaxVer = it->m_version;
    time_t nMaxTime = 0;
    for (; it != pdata->m_List.end(); ++it) {
      int nID = CBondContainer::instance().GetBondIndex(it->m_bondkey,
                                                        it->m_listedmarket);
      if (nID < 0) continue;
      const CBondInfo& bond = CBondContainer::instance().ElementAtR(nID);
      if (!bond.IsValidBond()) continue;
      bool bNCD = bond.IsBondNCD();
      if (bNCD && !NCDValid) continue;
      if (!bNCD && !BondValid) continue;

      bool bAuthValid{true};
      if (strcmp(it->m_company_id, "e") == 0) {
        bAuthValid = uam.HasExchangeAuth(bond.GetListedMarket());
      }
      if (!bAuthValid) continue;

      memset(&report, 0, sizeof(REPORT));
      FIELDCOPY(report.m_sBondKey, it->m_bondkey);
      FIELDCOPY(report.m_company_id, it->m_company_id);
      FIELDCOPY(report.m_bp_status, it->m_bp_status);
      FIELDCOPY(report.m_price_status, it->m_price_status);
      FIELDCOPY(report.m_sListedMarket, it->m_listedmarket);
      FIELDCOPY(report.m_tradePrice, it->m_tradePrice);
      report.m_create_time = it->m_create_time;
      report.m_time = it->m_modify_time;
      report.m_dwVersion = it->m_version;
      ReportWithxQBBondQuote_c(report, *it);

      if (bond.IsTransBond() && bIsEx) {
        int sym = atoi(it->m_symbol);
        if (sym == 1) {
          if (it->m_clean_price[0] != '\0')
            FIELDCOPY(report.m_bidinfo.m_sPrice, it->m_clean_price);
          else
            FIELDCOPY(report.m_bidinfo.m_sPrice, it->m_price);
        } else if (sym == -1) {
          if (it->m_clean_price[0] != '\0')
            FIELDCOPY(report.m_askinfo.m_sPrice, it->m_clean_price);
          else
            FIELDCOPY(report.m_askinfo.m_sPrice, it->m_price);
        }
        if (it->m_trade_clear_Price[0] != '\0')
          FIELDCOPY(report.m_tradePrice, it->m_trade_clear_Price);
        else
          FIELDCOPY(report.m_tradePrice, it->m_tradePrice);
      } else {
        FIELDCOPY(report.m_tradePrice, it->m_tradePrice);
      }

      nMaxTime = max(nMaxTime, report.m_create_time);
      if (it->m_version < nMinVer) nMinVer = it->m_version;
      if (it->m_version > nMaxVer) nMaxVer = it->m_version;

      report.m_price_sel = Trade_Price;
      if (funcId == E_FID_QB_BONDCOP_BEST_PRICE_PUSH) {
        //?请求机构二级债券最优报价
        // TODO
        // bRet = UpdateQuoteManagerByREPORT(HYQuotMng, &report, true,
        // atoi(it->m_symbol));
      } else {
        UpdateBondContainerByREPORT(CBondContainer::instance(), &report, true,
                                    true, nullptr, atoi(it->m_symbol));
        // bool isValid = (strcmp(it->m_price_status, "0") != 0 &&
        // strcmp(it->m_bp_status, "0") == 0);
        // TODO:价格提醒?

        std::string bondkey(it->m_bondkey);
        bondkey.append(".").append(it->m_listedmarket);
        m_bondBestPrice[bondkey].push_back(*it);
        m_bpAll.push_back(*it);
      }
    }

    if (funcId != E_FID_QB_BONDCOP_BEST_PRICE_PUSH) {
      BondUtility::updateBestPriceVersionByID(
          CBondContainer::instance(), pdata->m_List.begin()->m_company_id,
          nMinVer, nMaxVer, nMaxTime);
    }

    if (!m_bpAll.isEmpty()) emit bestPriceArrivedAll(m_bpAll);

    for (const auto& bp : m_bondBestPrice) {
      emit bestPriceArrived(bp.first, bp.second);
    }

    msgEventDispatcher.dispatch(EVENT_MESSAGE_ARRIVED, &msg);
  } else if (funcId == E_FID_CSI_PRICE_ALL_REQ_V2) {
    if (!msg.m_pRet) return;

    CBondCSInfo::instance().add((xCSIList_c*)msg.m_pRet);
  } else if (funcId == E_FID_QB_BOND_LIQUIDITY_FULL_REQ_V2) {
    xQBBondLiquidityFullAck_c* pdata = (xQBBondLiquidityFullAck_c*)msg.m_pRet;
    if (!pdata) return;
    CBondLiquidity::instance().UpdateLiquidity(pdata);
  } else if (funcId == E_FID_QB_ISSUER_LIQUIDITY_FULL_REQ_V2) {
    xQBIssuerLiquidityFullAck_c* pdata =
        (xQBIssuerLiquidityFullAck_c*)msg.m_pRet;
    if (!pdata) return;
    CIssuerLiquidity::instance().UpdateLiquidity(pdata);
  } else if (funcId == E_FID_QB_HIGT_YIELD_BOND_QRY) {
    xQBHighYieldBondListAck_c* pdata = (xQBHighYieldBondListAck_c*)msg.m_pRet;
    if (!pdata) return;
    CHighYieldBond::instance().UpdateData(pdata);
  } else if (funcId == E_FID_QB_THIRD_PARTY_GUARANTEE_QRY) {
    xQBThirdPartyGuaranteeListAck_c* pdata =
        (xQBThirdPartyGuaranteeListAck_c*)msg.m_pRet;
    if (!pdata) return;
    CThirdPartyGuarantee::instance().UpdateData(pdata);
  } else if (funcId == E_FID_QB_SECTOR_BOND_REQ) {
    SectorBondAck* pdata = (SectorBondAck*)msg.m_pRet;
    if (!pdata) return;
    SectorBond::instance().UpdateData(pdata);
  } else if (funcId == E_FID_MARKETMAKE_TARGET_BOND_REQ) {
    xQBMarketMakeTargetAck_c* pdata = (xQBMarketMakeTargetAck_c*)msg.m_pRet;
    if (!pdata) return;
    CMarketMakeTarget::instance().UpdateData(pdata);
  } else if (funcId == E_FID_QB_ABBOND_RECOMMEND_PRICE_REQ) {
    xQBAbBondRecommendPriceAck_t* pdata =
        (xQBAbBondRecommendPriceAck_t*)msg.m_pRet;
    if (!pdata) return;
    CABBondPriceInfo::instance().UpdateData(pdata);
  } else if (funcId == E_FID_QB_MIXED_BESTQUOTE_REQ) {
    xQBMixedBestQuoteAck_c* pdata = (xQBMixedBestQuoteAck_c*)msg.m_pRet;
    if (!pdata || pdata->m_list.size() == 0) return;

    for (std::list<xQBMixedBestQuoteUnit_c>::iterator it =
             pdata->m_list.begin();
         it != pdata->m_list.end(); ++it) {
      int nID = CBondContainer::instance().GetBondIndex(it->m_bondkey,
                                                        it->m_listedmarket);
      if (nID < 0) continue;

      const CBondInfo& bond = CBondContainer::instance().ElementAtR(nID);
      if (!bond.IsValidBond()) continue;

      REPORT report;
      memset(&report, 0, sizeof(REPORT));
      ReportWithxQBMixedBestPrice(report, *it, bond.IsRight());
      UpdateMixedBestPrice(&report);
    }

    if (msg.m_IsReceving != 0 && msg.m_Index % 2 > 0) return;

    emit mixedBestPriceArrived();
  } else if (funcId == E_FID_QB_MIXED_BESTQTUOE_PUSH) {
    xQBMixedBestQuoteAck_c* pdata = (xQBMixedBestQuoteAck_c*)msg.m_pRet;
    if (!pdata || pdata->m_list.size() == 0) return;

    QList<xQBMixedBestQuoteUnit_c> pushList;
    for (std::list<xQBMixedBestQuoteUnit_c>::const_iterator itor =
             pdata->m_list.begin();
         itor != pdata->m_list.end(); itor++) {
      pushList.push_back(*itor);
    }

    emit mixedBestPricePush(pushList);
  }
}

void BondDataCenter::saveMarketStreamDeal(const qb::SSAckMsg& msg) {
  bool bRet = false;
  xQBMarketStreamList_c* pdata = (xQBMarketStreamList_c*)msg.m_pRet;
  if (!pdata) return;
  std::list<xQBMarketStreamUnit_c>::const_iterator it = pdata->m_List.begin();

  if (strcmp(it->m_company_id, "c") != 0 &&
      strcmp(it->m_company_id, "e") != 0) {
    bool BondValid = SSUserAccountManager::instance().IsBrokerBondAvailable(
        it->m_company_id);
    bool NCDValid =
        SSUserAccountManager::instance().IsBrokerNCDAvailable(it->m_company_id);
    if (!BondValid && !NCDValid) {
      return;
    }
    if (!BondValid && strcmp(pdata->m_BusinessCode, "BOND") == 0) {
      return;
    }
    if (!NCDValid && strcmp(pdata->m_BusinessCode, "NCD") == 0) {
      return;
    }
    CMarketStream::bondStream().InsertCashData(pdata, bRet);
    CMarketStream::bondStream().Save();
  }
}

void BondDataCenter::notifyMarketStreamDeal(const qb::SSAckMsg& msg) {
  xQBMarketStreamList_c* lstPush = (xQBMarketStreamList_c*)msg.m_pRet;
  QB_CHECK_RETURN_VOID1(lstPush);

  std::map<QString, QList<xQBMarketStreamUnit_c>> mapPush;
  QList<xQBMarketStreamUnit_c> allmks;
  for (std::list<xQBMarketStreamUnit_c>::const_iterator itor =
           lstPush->m_List.begin();
       itor != lstPush->m_List.end(); itor++) {
    QString strBondKey(itor->m_body2.m_bondkey);
    strBondKey.append(".");
    strBondKey.append(itor->m_body2.m_listedmarket);
    mapPush[strBondKey].push_back(*itor);
    allmks.push_back(*itor);
  }

  for (auto it = mapPush.begin(); it != mapPush.end(); it++) {
    emit dealMarketPush(msg.m_FuncID, it->first, it->second);
  }

  emit dealMarketPushAll(msg.m_FuncID, allmks);

  msgEventDispatcher.dispatch(EVENT_MESSAGE_ARRIVED, &msg);
}

void BondDataCenter::subMixedBPPush(const char* contributorId) {
  doMixedBestQuote(E_FID_QB_MIXED_BESTQTUOE_PUSH, contributorId);
}

void BondDataCenter::unSubMixedBPPush(const char* contributorId) {
  doMixedBestQuote(E_FID_QB_MIXED_BESTQTUOE_PUSH_CANCEL, contributorId);
}

void BondDataCenter::doMixedBestQuote(int funId, const char* contributorId) {
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = funId;

  xQBMixedBestQuoteReq req;
  xQBMixedBestQuoteReq* ptr = &req;
  FIELDCOPY(ptr->m_contributorId, contributorId);
  ptr->m_versionFrom = CBondContainer::instance().GetVersionById(contributorId);
  ptr->m_versionTo = 0;
  Req.m_pRequest = (void*)ptr;

  MessagePoster poster(
      &Req, [=](qb::proto::Message& msg, qb::SSRequestMsg* req) {
        xQBMixedBestQuoteReq* pdata = (xQBMixedBestQuoteReq*)req->m_pRequest;
        qb::proto::VariantMap submsg;
        submsg.setString("contributorId", pdata->m_contributorId);
        submsg.SetInt32("versionFrom", pdata->m_versionFrom);
        submsg.SetInt32("versionTo", pdata->m_versionTo);
        msg.SetMap("xQBMixedBestQuoteReq", submsg);
      });
  poster.send(this);
}

BondDataCenter::BondDataCenter() {
  PushMsgInfo pmi(E_FID_QB_EX_DEAL_PUSH_V2, "", nullptr);
  registPush(pmi, nullptr, nullptr);

  PushMsgInfo pmi2(E_FID_QB_EX_DEAL_PUSH, "", nullptr);
  registPush(pmi2, nullptr, nullptr);

  PushMsgInfo pmi3(E_FID_QB_MARKET_STREAM_DEAL_PUSH, "", nullptr);
  registPush(pmi3, nullptr, nullptr);

  PushMsgInfo pmi4(E_FID_QB_CFETS_DEAL_PUSH, "", nullptr);
  registPush(pmi4, nullptr, nullptr);

  PushMsgInfo pmi5(E_FID_QB_BEST_PRICE_PUSH_V2, "", nullptr);
  registPush(pmi5, nullptr, nullptr);

  PushMsgInfo pmi6(E_FID_QB_MIXED_BESTQTUOE_PUSH, "", nullptr);
  registPush(pmi6, nullptr, nullptr);

  qRegisterMetaType<QList<xQBMarketStreamUnit_c>>(
      "QList<xQBMarketStreamUnit_c>");
  qRegisterMetaType<QList<xQBBestPriceUnit_c>>("QList<xQBBestPriceUnit_c>");
  qRegisterMetaType<QList<xQBMixedBestQuoteUnit_c>>(
      "QList<xQBMixedBestQuoteUnit_c>");
  qRegisterMetaType<std::string>("std::string");
  qRegisterMetaType<QList<int>>("QList<int>");
  qRegisterMetaType<QList<QString>>("QList<QString>");
  qRegisterMetaType<QList<xQBSHFIQuoteUnit_c>>("QList<xQBSHFIQuoteUnit_c>");
  qRegisterMetaType<QList<xQBExQuoteUnit_c>>("QList<xQBExQuoteUnit_c>");
}
